package framework;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import massobjects.BaseMass;
import massobjects.FixedMass;
import massobjects.Mass;
import simulation.Assembly;
import simulation.Simulation;
import springobjects.BaseConnector;
import springobjects.Muscle;
import springobjects.Spring;


/**
 * Loads all input files and adds them to the simulation.
 * 
 * @author Robert C. Duvall
 * @modified David Howdyshell, Zack Hopping
 */
public class Factory {
    private static final int BAR_HIGH_K = 50;

    /**
     * Parses input file, creates a new assembly, and adds it to the simulation.
     * 
     * @param sim - the simulation
     * @param modelFile - file to be loaded in
     */
    public void loadModel (Simulation sim, File modelFile) {
        try {
            Assembly newAssembly = new Assembly();
            Scanner input = new Scanner(modelFile);
            while (input.hasNext()) {
                Scanner line = new Scanner(input.nextLine());
                if (line.hasNext()) {
                    String type = line.next();
                    if ("mass".equals(type)) {
                        newAssembly.add(massCommand(line));
                    }
                    else if ("spring".equals(type)) {
                        newAssembly.add(springCommand(line, newAssembly));
                    }
                    else if ("muscle".equals(type)) {
                        newAssembly.add(muscleCommand(line, newAssembly));
                    }
                }
            }
            sim.add(newAssembly);
            input.close();
        }
        catch (FileNotFoundException e) {
            // should not happen because File came from user selection
            e.printStackTrace();
        }
    }

    /**
     * Loads the global forces for this simulation.
     * @param sim - the simulation
     * @param globalForceFile - input force file to be parsed
     */
    public void loadGlobalForces (Simulation sim, File globalForceFile) {
        try {
            Scanner input = new Scanner(globalForceFile);
            while (input.hasNext()) {
                Scanner line = new Scanner(input.nextLine());
                if (line.hasNext()) {
                    String type = line.next();
                    if ("gravity".endsWith(type)) {
                        sim.getForceHandler().setGravity(line);
                    }
                    else if ("viscosity".equals(type)) {
                        sim.getForceHandler().setViscosity(line);
                    }
                    else if ("centermass".equals(type)) {
                        sim.getForceHandler().setCenterMass(line);
                    }
                    else if ("wall".equals(type)) {
                        sim.getForceHandler().setWallForce(line);
                    }
                }
            }
            input.close();
        }
        catch (FileNotFoundException e) {
            // should not happen because File came from user selection
            e.printStackTrace();
        }
    }

    private BaseMass massCommand (Scanner line) {
        int id = line.nextInt();
        double x = line.nextDouble();
        double y = line.nextDouble();
        double mass = line.nextDouble();
        if (mass <= 0) { return new FixedMass(id, x, y); }
        return new Mass(id, x, y, mass);
    }

    private BaseConnector springCommand (Scanner line, Assembly assem) {
        int m1 = line.nextInt();
        int m2 = line.nextInt();
        double restLength = line.nextDouble();
        double ks = line.nextDouble();
        // handle different if a bar
        if (ks < 0) {
            restLength = Force.distanceBetween(assem.getMass(m1).getCenter(),
                    assem.getMass(m2).getCenter());
            ks = BAR_HIGH_K;
        }
        return new Spring(assem.getMass(m1), assem.getMass(m2), restLength, ks);
    }

    private BaseConnector muscleCommand (Scanner line, Assembly assem) {
        int m1 = line.nextInt();
        int m2 = line.nextInt();
        double restLength = line.nextDouble();
        double ks = line.nextDouble();
        double amplitude = line.nextDouble();
        return new Muscle(assem.getMass(m1), assem.getMass(m2), restLength, ks,
                amplitude);
    }

}
